#include <stdio.h>
#include <sys/time.h>
#include <stdlib.h>
#include <signal.h>

struct itimerval realtime;
struct itimerval usermode;
struct itimerval profmode;
volatile sig_atomic_t keep_going = 1;
int starttime;


void real_alarm(int sig)
{
	keep_going = 0;
	signal(sig, real_alarm);
}

void other_alarm(int sig)
{
	signal(sig, other_alarm);
}

unsigned long fibonacci(unsigned int n)
{
  if(keep_going==0)
	{
	int usertime;
	int kerneltime;
	getitimer(ITIMER_VIRTUAL, &usermode);
    getitimer(ITIMER_PROF, &profmode);
	usertime = (starttime - usermode.it_value.tv_sec-1)*1000 + (1000000 - usermode.it_value.tv_usec)/1000;
	kerneltime =  (starttime - profmode.it_value.tv_sec-1)*1000 + (1000000 - profmode.it_value.tv_usec)/1000 - usertime;
	printf("User mode time: %d ms\n", usertime);
	printf("Kernel mode time: %d ms\n", kerneltime);
	exit(0);
	}
  if (n == 0)
    return 0;
  else if (n == 1 || n == 2)
    return 1;
  else
    return fibonacci(n-1) + fibonacci(n-2);
}

int main(int argc, char *argv[])
{
  unsigned long fib; 
  int n, t;
  if (argc != 3) {
    printf("Usage: profile n t\n");
    exit(1);
  }
  n = atoi(argv[1]);
  t = atoi(argv[2]);
  signal(SIGALRM, real_alarm);
  signal(SIGVTALRM, other_alarm);
  signal(SIGPROF, other_alarm);
  starttime = t;
  realtime.it_value.tv_sec = t;
  usermode.it_value.tv_sec = t;
  profmode.it_value.tv_sec = t;
  setitimer(ITIMER_VIRTUAL, &usermode, NULL);
  setitimer(ITIMER_REAL, &realtime, NULL);
  setitimer(ITIMER_PROF, &profmode, NULL);
  fib = fibonacci(n);
  return 0;
}
